package m3channel

import (
	"fmt"
	"time"
)

// 无缓冲的通道
func ChannelDemo1() {
	// 1. channel的定义
	// 2. channel初始化

	var ch1 chan int
	fmt.Println(ch1)

	ch2 := make(chan int)
	fmt.Println(ch2)

	// 4. channel操作、发送、接受、关闭
	ch2 <- 10

	number := <-ch2
	fmt.Println(number)

	// 造成死锁原因：当前方法也是协程，channel写入数据时会阻塞当前协程，只有channel有人读取数据，所以需要新启动协程处理
	time.Sleep(time.Second)
}

func ChannelDemo2() {
	// 1. channel的定义
	// 2. channel初始化

	var ch1 chan int
	fmt.Println(ch1)

	ch2 := make(chan int)
	fmt.Println(ch2)

	// 4. channel操作、发送、接受、关闭
	go func() {
		ch2 <- 10
	}()

	go func() {
		number := <-ch2
		fmt.Println(number)
	}()

	time.Sleep(time.Second)
}

// 3. 有缓冲的通道
func ChannelDemo3() {
	// 1. channel的定义
	// 2. channel初始化

	var ch1 chan int
	fmt.Println(ch1)

	ch2 := make(chan int, 1)
	fmt.Println(ch2)

	// 4. channel操作、发送、接受、关闭
	ch2 <- 10

	number := <-ch2
	fmt.Println(number)

	// 造成死锁原因：当前方法也是协程，channel写入数据时会阻塞当前协程，只有channel有人读取数据，所以需要新启动协程处理
	time.Sleep(time.Second)
}

// 1.1.7. close()
func ChannelDemo4() {
	c := make(chan int)
	go func() {
		for i := 0; i < 5; i++ {
			c <- i
		}
		close(c)
	}()

	for {
		if data, ok := <-c; ok {
			fmt.Println(data)
		} else {
			break
		}
	}
	fmt.Println("main结束")
}

// 1.1.8. 如何优雅的从通道循环取值
func ChannelDemo5() {
	ch1 := make(chan int)
	ch2 := make(chan int)
	// 开启goroutine将0~100的数发送到ch1中
	go func() {
		for i := 0; i < 10; i++ {
			fmt.Println("set ", i)
			ch1 <- i
		}
		close(ch1)
	}()
	// 开启goroutine从ch1中接收值，并将该值的平方发送到ch2中
	go func() {
		for {
			i, ok := <-ch1 // 通道关闭后再取值ok=false
			fmt.Println("get ", i, ok)
			if !ok {
				break
			}
			ch2 <- i
		}
		close(ch2)
	}()
	// 在主goroutine中从ch2中接收值打印
	for i := range ch2 { // 通道关闭后会退出for range循环
		fmt.Println("range ", i)
	}
}

// 1.1.9. 单向通道
// 有的时候我们会将通道作为参数在多个任务函数间传递，很多时候我们在不同的任务函数中使用通道都会对其进行限制，比如限制通道在函数中只能发送或只能接收。
func counter(out chan<- int) {
	for i := 0; i < 100; i++ {
		out <- i
	}
	close(out)
}

func squarer(out chan<- int, in <-chan int) {
	for i := range in {
		out <- i * i
	}
	close(out)
}

func printer(in <-chan int) {
	for i := range in {
		fmt.Println(i)
	}
}

func ChannelDemo6() {
	ch1 := make(chan int)
	ch2 := make(chan int)
	go counter(ch1)
	go squarer(ch2, ch1)
	printer(ch2)
}


